#include "base_time.h"
#include "base_log.h"

#include <string.h>
#include <ctime>

namespace El {
namespace Base {

TimeManager &TimeManager::GetInstance()
{
    static TimeManager instance;
    return instance;
}

TimeManager::TimeManager() : running_(false), min_jump_interval_(DEFAULT_MIN_JUMP_INTERVAL) {}

TimeManager::~TimeManager()
{
    StopJumpDetection();
}

// 启动时间同步
void TimeManager::Start()
{
    SyncRtcToSystem();
    StartJumpDetection();
}

// 停止时间同步
void TimeManager::Stop()
{
    StopJumpDetection();
}

// 同步rtc时间到系统时间
void TimeManager::SyncRtcToSystem()
{
    if (system("hwclock -s") == -1) {
        LOG_ERROR("Failed to sync RTC to system time");
    }
}

// 同步系统时间到rtc时间
void TimeManager::SyncSystemToRtc()
{
    if (system("hwclock -w") == -1) {
        LOG_ERROR("Failed to sync system time to RTC");
    }
}

int32_t TimeManager::Register(std::function<void(int64_t)> callback)
{
    return jump_callbacks_.Register(callback);
}

void TimeManager::Unregister(int32_t handle)
{
    jump_callbacks_.Unregister(handle);
}

void TimeManager::StartJumpDetection()
{
    if (running_) {
        return;
    }

    running_ = true;
    detector_thread_ = std::thread(&TimeManager::DetectorThread, this);
}

void TimeManager::StopJumpDetection()
{
    if (!running_) {
        return;
    }

    running_ = false;
    if (detector_thread_.joinable()) {
        detector_thread_.join();
    }
}

void TimeManager::SetMinJumpInterval(int64_t seconds)
{
    min_jump_interval_ = seconds > 0 ? seconds : DEFAULT_MIN_JUMP_INTERVAL;
}

int64_t TimeManager::GetMinJumpInterval() const
{
    return min_jump_interval_;
}

void TimeManager::DetectorThread()
{
    auto last_time = std::chrono::system_clock::now();
    last_jump_time_ = std::chrono::steady_clock::now();

    while (running_) {
        std::this_thread::sleep_for(std::chrono::seconds(1));

        auto current_time = std::chrono::system_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::seconds>(current_time - last_time).count();

        if (std::abs(duration - 1) > 1) {
            auto now = std::chrono::steady_clock::now();
            auto since_last_jump = std::chrono::duration_cast<std::chrono::seconds>(now - last_jump_time_).count();

            if (since_last_jump >= min_jump_interval_) {
                int64_t jump_seconds = duration - 1;
                last_jump_time_ = now;

                LOG_INFO("Time jumped by {} seconds, syncing to RTC", jump_seconds);
                SyncSystemToRtc();
                jump_callbacks_.InvokeAll(jump_seconds);
            }
        }

        last_time = current_time;
    }
}

} // namespace Base
} // namespace El